import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;

public class Node {
    Token token;
    ArrayList<Node> children;
    private Node parent;
    private Integer nodeID;
    
    public Node(Integer id, Node creator){
    	parent = creator;
    	setNodeID(id);
        children = new ArrayList<Node>();
    }
    public Node(Token t, Integer id, Node creator){
    	setParent(creator);
    	setNodeID(id);
        children = new ArrayList<Node>();
        token = t;
    }
    
    public void addChild(Node n){
        children.add(n);
    }

    public Node get(Integer i){
        return children.get(i);
    }

    public void setToken(Token t){
        token = t;
    }

// added for convience sake, calls the token's method.
    public TokenClass getType(){
        return token.getType();
    }
     public String getLiteral(){
        return token.getLiteral();
    }
    
    public Token getToken(){
        return token;
    }

    public ArrayList<Node> getChildren(){
        return children;
    }

	public String toString(){
        String s = "Node\n";
        s += "token:" + token + "\n";
        s += "Children:" + children.toString().replaceAll("\n","\n  ") +")";
        return s;
    }

    public void trim(){
        //to avoid concurrent modification errors
        ArrayList<Node> toRemove = new ArrayList<Node>();
        //if this node is useless, remove it
        if(token == null && children.size() == 1){
            token = children.get(0).getToken();
            children = children.get(0).getChildren();
            //once the useless node is removed we recurse
            trim();
        }else{
            for(Node i: children){
                //this node is a useless leaf, simply prune it
                if(i.getToken() == null && i.getChildren().size() == 0){
                    toRemove.add(i);
                }else{
                    //call trim() on its children
                    i.trim();
                }
            }
            //remove all of the useless leaves
            for(Node i: toRemove){
                children.remove(i);
            }
        }
    }
    
	Node getParent() {
		return parent;
	}

	void setParent(Node parent) {
		this.parent = parent;
	}

    public Integer size(){
        return children.size();
    }
	
	public void printTree()
	{
		System.out.println("Node: " + getNodeID());
		System.out.println("Num children: " + children.size());
		
		// Print parent number if available
		if(parent != null)
		{
			System.out.println("Parent ID: " + parent.getNodeID());
		}
		else
		{
			System.out.println("Parent is null");
		}
		
		// Print token info if available
		if(token != null)
		{
			System.out.println("Token Type: " + token.getType());
			System.out.println("Token val: " + token.getLiteral());
		}
		else
		{
			System.out.println("Token is null");
		}
		
		// Print spacing line
		System.out.println();
		
		// Do ALL the THINGS!
		for(Node n : children)
		{
			n.printTree(); 
		}
	}
	
	Integer getNodeID() {
		return nodeID;
	}
	void setNodeID(Integer nodeID) {
		this.nodeID = nodeID;
	}
}
        
